#pragma once
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
#include "../comm/log.hpp"
#include "../comm/util.hpp"
#include "./compile.hpp"
#include "./runner.hpp"
namespace compile_and_run
{
    using namespace util;
    class CompileAndRun
    {
    public:
        static void RemoveTempFile(const std::string &file_name)
        {
            std::string _src = util::PathUtil::Src(file_name);
            if(util::FileUtil::IsFileExists(_src)) unlink(_src.c_str());//删除文件的系统调用函数
            std::string _exe = util::PathUtil::Exe(file_name);
            if(util::FileUtil::IsFileExists(_exe)) unlink(_exe.c_str());
            std::string _compiler_error = util::PathUtil::CompileError(file_name);
            if(util::FileUtil::IsFileExists(_compiler_error)) unlink(_compiler_error.c_str());
            std::string _stdin = util::PathUtil::Stdin(file_name);
            if(util::FileUtil::IsFileExists(_stdin)) unlink(_stdin.c_str());
            std::string _stdout = util::PathUtil::Stdout(file_name);
            if(util::FileUtil::IsFileExists(_stdout)) unlink(_stdout.c_str());
            std::string _stderr = util::PathUtil::Stderror(file_name);
            if(util::FileUtil::IsFileExists(_stderr)) unlink(_stderr.c_str());
        }
        static std::string CodeToDesc(int code,std::string &file_name)
        {
            std::string desc;
            switch (code)
            {
            case 0:
                desc = "编译成功";
                break;
            case -1:
                desc = "提交的代码是空";
                break;
            case -2:
                desc = "未知错误";
                break;
            case -3:
                util::FileUtil::ReadFile(util::PathUtil::CompileError(file_name),&desc,true);
                // std::cout << desc << endl;
                break;
            case SIGABRT: // 6
                desc = "内存超过范围";
                break;
             case SIGXCPU: // 24
                desc = "CPU使用超时";
                break;
            case SIGFPE: // 8
                desc = "浮点数溢出";
                break;
            default:
                desc = "未知: " + std::to_string(code);
                break;
            }
            return desc;
        }
        static void Start(std::string &in_json,std::string *out_json)
        {
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json,in_value);
            std::string code = in_value["code"].asString();
            std::string input = in_value["input"].asString();
            int cpu_limit = in_value["cpu_limit"].asInt();
            int mem_limit = in_value["mem_limit"].asInt();
            std::string file_name;
            Json::Value out_value;
            int state_code = 0;
            int run_code = 0;
            if(code.size() == 0)
            {
                state_code = -1;//表示代码为空
                goto END;
            }
            // 形成的文件名只具有唯一性，没有目录没有后缀
            // 毫秒级时间戳+原子性递增唯一值: 来保证唯一性
            file_name = util::TimeUtil::GetTimeMS();
            if(!util::FileUtil::WirteFile(PathUtil::Src(file_name),code))
            { 
                state_code = -2; //未知错误
                goto END;
            }
            if(!compile::Compile::Compiled(file_name))
            {
                state_code = -3;//表示编译失败
                goto END;
            }
            run_code = runners::Runner::Run(file_name,cpu_limit,mem_limit);
            if(run_code > 0)
            {
                state_code = run_code;
                goto END;
            }
            else if(run_code < 0)
            {
                state_code = -2;
                goto END;
            }
            else
            {
                //运行成功
                state_code = 0;
                goto END;
            }
            END:
                out_value["status"] = state_code;
                out_value["reason"] = CodeToDesc(state_code,file_name);
                if(state_code == 0)
                {
                    std::string stdout;
                    util::FileUtil::ReadFile(PathUtil::Stdout(file_name),&stdout,true);
                    out_value["stdout"] = stdout;

                    std::string stderr;
                    util::FileUtil::ReadFile(PathUtil::Stderror(file_name),&stderr,true);
                    out_value["stderr"] = stderr;
                }
                Json::StyledWriter writer;
                *out_json = writer.write(out_value);
                RemoveTempFile(file_name);
        }
    };
}